package us.kg.kotoriforest.senior.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * ClassName: us.kg.kotoriforest.senior.util.JDBCUtilVer2 </br>
 * Description: 使用 ThreadLocal 来改进工具类
 * 该工具类的目的为 ① 维护一个连接池对象供整个项目使用
 * ② 维护一个 ThreadLocal 对象 保证同一个线程在对数据库进行操作时只会使用同一个 Connection 而不是每次操作都需要再重新获取一个 Connection
 * ③ 对外暴露提供和回收连接的方法 连接的提供和释放需要借助 ThreadLocal 来进行处理 </br>
 * 注：每一个线程都有一个独属于自己的 ThreadLocalMap（其实就是一个Entry&lt;ThreadMap, Object&gt;）
 * 这个对象只有其所属的线程借助 ThreadLocal 类中方法才能进行操作 所以我们可以把 ThreadLocal&lt;Object&gt;看作是 Object 的包装类
 * 这个包装类让其中的对象是属于线程的 只有当前线程可见 其他线程不可见
 *
 * @author Kotori rotroutine@163.com
 * @version 2.0
 * @since 2024/11/29
 */
public abstract class JDBCUtilVer2 {
    private static final DataSource DATA_SOURCE;
    private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();

    static {
        Properties properties = new Properties();
        try (InputStream resourceAsStream = JDBCUtilVer2.class.getClassLoader().getResourceAsStream("db.properties")) {
            properties.load(resourceAsStream);

            DATA_SOURCE = DruidDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Connection getConnection() throws SQLException {
        // 从 ThreadLocal 中获取 Connection
        Connection connection = threadLocal.get();
        if (null == connection) {
            connection = DATA_SOURCE.getConnection();
            threadLocal.set(connection);
        }

        return connection;
    }

    public static void close() throws RuntimeException {
        Connection connection = threadLocal.get();
        if (null != connection) {
            threadLocal.remove();
            try {
                connection.setAutoCommit(true);
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
